package dd.prog2.musterExercises.ws12set13_4_mvc.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.util.Observable;
import java.util.Observer;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JToolBar;

/**
 * Provides a view for the Connect Four Application. It is responsible for all
 * presentation aspects. Swing components are used for this purpose. The view
 * delegates activities in response to mouse events to a
 * <code>ConnectFourController</code>, observes a <code>ConnectFourModel</code>,
 * and updates after each change of the model state.
 * 
 * @author Ruediger Lunde
 */
@SuppressWarnings("serial")
public class ConnectFourView extends JFrame implements Observer {

	public final static String CLEAR_CMD = "Clear";
	public final static String PROPOSE_MOVE_CMD = "Propose Move";

	private ConnectFourModel model;

	// create attributes for all parts of the application which need to be
	// accessed by listeners, inner classes, and helper methods

	JComboBox strategyCombo;
	JComboBox timeCombo;
	private JButton clearButton;
	private JButton proposeButton;
	private JPanel boardPanel;
	private JLabel statusBar;

	/** Constructs the game frame and makes it visible. */
	public ConnectFourView(ConnectFourModel model, ConnectFourController controller) {
		this.model = model;
		controller.setView(this);

		setTitle("Connect Four");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		JToolBar toolBar = new JToolBar();
		toolBar.setFloatable(false);
		strategyCombo = new JComboBox(new String[] { "Advanced Alpha-Beta",
				"Advanced Alpha-Beta (debug)" });
		strategyCombo.setSelectedIndex(0);
		toolBar.add(strategyCombo);
		timeCombo = new JComboBox(new String[] { "5sec", "10sec", "15sec",
				"20sec" });
		timeCombo.setSelectedIndex(0);
		toolBar.add(timeCombo);
		toolBar.add(Box.createHorizontalGlue());
		clearButton = new JButton("Clear");
		clearButton.setActionCommand(CLEAR_CMD);
		clearButton.addActionListener(controller);
		toolBar.add(clearButton);
		proposeButton = new JButton(PROPOSE_MOVE_CMD);
		proposeButton.setActionCommand("Propose Move");
		proposeButton.addActionListener(controller);
		toolBar.add(proposeButton);
		add(toolBar, BorderLayout.NORTH);

		int rows = model.getRows();
		int cols = model.getCols();
		boardPanel = new JPanel();
		boardPanel.setLayout(new GridLayout(rows, cols, 5, 5));
		boardPanel.setBorder(BorderFactory.createEtchedBorder());
		boardPanel.setBackground(Color.BLUE);
		for (int i = 0; i < rows * cols; i++) {
			GridElement element = new GridElement(i / cols, i % cols);
			boardPanel.add(element);
			element.addActionListener(controller);
		}
		add(boardPanel, BorderLayout.CENTER);
		statusBar = new JLabel();
		getContentPane().setBackground(Color.BLUE);
		statusBar.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
		add(statusBar, BorderLayout.SOUTH);
		update(null, null);
	}

	private boolean isDebugModeEnabled() {
		return strategyCombo.getSelectedIndex() == 1;
	}

	/** Updates the view after the model state has changed. */
	@Override
	public void update(Observable o, Object arg) {
		boardPanel.repaint(); // paint all disks!

		String statusText;
		if (!model.isGameOver()) {
			String toMove = (String) model.getPlayerForNextMove();
			statusText = "Next move: " + toMove;
			statusBar.setForeground(toMove.equals("red") ? Color.RED
					: Color.YELLOW);
		} else {
			String winner = model.getWinner();
			if (winner != null)
				statusText = "Color " + winner + " has won. Congratulations!";
			else
				statusText = "No winner :-(";
			statusBar.setForeground(Color.WHITE);
		}
		if (isDebugModeEnabled() && model.searchMetrics != null)
			statusText += "    " + model.searchMetrics;
		statusBar.setText(statusText);
	}

	// //////////////////////////////////////////////////////////////
	// inner classes

	/** Represents a space within the grid where discs can be placed. */
	class GridElement extends JButton {
		int row;
		int col;

		GridElement(int row, int col) {
			this.row = row;
			this.col = col;
			setBackground(Color.BLUE);
		}

		public void paintComponent(Graphics g) {
			super.paintComponent(g); // should have look and feel of a button...
			ConnectFourModel model = ConnectFourView.this.model;
			String player = model.getPlayerAt(row, col);
			if (player != null) {
				drawDisk(g, player); // draw disk on top!
			} else if (isDebugModeEnabled())
				for (String p : model.getPlayers())
					if (model.isWinPositionFor(row, col, p))
						drawWinSituation(g, p);
		}

		/** Fills a simple oval. */
		void drawDisk(Graphics g, String player) {
			int size = Math.min(getWidth(), getHeight());
			g.setColor(player.equals("red") ? Color.RED : Color.YELLOW);
			g.fillOval((getWidth() - size) / 2, (getHeight() - size) / 2, size,
					size);
		}

		/** Draws a simple oval. */
		void drawWinSituation(Graphics g, String player) {
			int size = Math.min(getWidth(), getHeight());
			g.setColor(player.equals("red") ? Color.RED : Color.YELLOW);
			int offset = player.equals("red") ? 1 : 2;
			g.drawOval((getWidth() - size) / 2 + offset, (getHeight() - size)
					/ 2 + offset, size - 2 * offset, size - 2 * offset);
		}
	}
}
